/*
**************************************************************************************
*Myriad Engine                                                                       *
*Copyright (C) 2006-2007, 5d Studios (www.5d-Studios.com)                            *
*                                                                                    *
*This library is free software; you can redistribute it and/or                       *
*modify it under the terms of the GNU Lesser General Public                          *
*License as published by the Free Software Foundation; either                        *
*version 2.1 of the License, or (at your option) any later version.                  *
*                                                                                    *
*This library is distributed in the hope that it will be useful,                     *
*but WITHOUT ANY WARRANTY; without even the implied warranty of                      *
*MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU                   *
*Lesser General Public License for more details.                                     *
*                                                                                    *
*You should have received a copy of the GNU Lesser General Public                    *
*License along with this library; if not, write to the Free Software                 *
*Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA      *
**************************************************************************************
*/
package leola.backend.interpreter;

import java.util.HashMap;
import java.util.Map;

import leola.backend.EvalException;
import leola.types.LeoObject;

/**
 * The symbol table for retrieving stored variables.
 * 
 * @author Tony
 *
 */
public class SymbolTable {

	/**
	 * Symbols
	 */
	private Map<String, LeoObject> symbols;
	
	/**	
	 */
	public SymbolTable() {
		this.symbols = new HashMap<String, LeoObject>();
	}
	
	/* (non-Javadoc)
	 * @see java.lang.Object#toString()
	 */
	@Override
	public String toString() {
		return this.symbols.toString();
	}
	
	/**
	 * Sets the other {@link SymbolTable}'s values in this one.
	 * @param other
	 */
	public void set(SymbolTable other) {		
		for(Map.Entry<String, LeoObject> entry: other.symbols.entrySet()) {
			LeoObject obj = entry.getValue();			
			this.put(entry.getKey(), obj);
		}
	}
	
	/**
	 * Retrieves a {@link LeoObject} stored
	 * @param symbol
	 * @return
	 */
	public LeoObject get(String symbol) {
		return this.symbols.get(symbol);
	}
	
	/**
	 * Places the symbol in the table.
	 * 
	 * @param symbol
	 * @param obj
	 */
	public void put(String symbol, LeoObject obj) {
		this.symbols.put(symbol, obj);
	}
	
	/**
	 * Sets the value.
	 * @param symbol
	 * @param obj
	 */
	public void set(String symbol, LeoObject obj) throws Exception {
		LeoObject originalValue = get(symbol);
		if ( originalValue != null && originalValue.isFinal() ) {
			throw new EvalException
				("The supplied variable is declared as FINAL: " + symbol + " and has been attempted to be modified.");
		}
		else {
			put(symbol, obj);
		}
	}
	
	/**
	 * Determines if the values are equal each other
	 * @param other
	 * @return
	 */
	public boolean leoEquals(SymbolTable other) {
		if ( this == other) {
			return true;
		}
		
		boolean isEquals = false;
		if ( this.symbols.size() == other.symbols.size() ) {
			
			isEquals = true;
			for(Map.Entry<String, LeoObject> entry: this.symbols.entrySet()) {
				LeoObject obj = other.get(entry.getKey());
				if ( obj == null || !isEquals ) {
					return false;
				}
				
				isEquals = isEquals && obj.eq(entry.getValue());
			}
		}
		
		return isEquals;
	}
	
	/**
	 * @return a deep copy of this object
	 */
	public SymbolTable clone() {
		SymbolTable clone = new SymbolTable();
		for(Map.Entry<String, LeoObject> entry: this.symbols.entrySet()) {
			LeoObject obj = entry.getValue();
			LeoObject clonedObj = (obj != null) ? obj.clone() : null;
			clone.put(entry.getKey(), clonedObj);
		}
		
		return clone;
	}
	
	/**
	 * Does a shallow copy
	 * @return a shallow copy
	 */
	public SymbolTable shallowClone() {
		SymbolTable clone = new SymbolTable();
		for(Map.Entry<String, LeoObject> entry: this.symbols.entrySet()) {
			LeoObject obj = entry.getValue();			
			clone.put(entry.getKey(), obj);
		}
		
		return clone;
	}
}
